package com.alibaba.citrus.cr.unified.inventory.facade.service;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.unified.inventory.contants.MessageBusinessCodeEnum;
import com.alibaba.citrus.cr.unified.inventory.contants.MessageEventCodeEnum;
import com.alibaba.citrus.cr.unified.inventory.functions.factory.AllocateOrderEntityFactory;
import com.alibaba.citrus.cr.unified.inventory.functions.handler.AllocateOrderStatusHandler;
import com.alibaba.citrus.cr.unified.inventory.functions.handler.AllocateOrderStatusHandlerManager;
import com.alibaba.citrus.cr.unified.inventory.functions.handler.PlanAllocateOrderStatusHandler;
import com.alibaba.citrus.cr.unified.inventory.model.AllocateOrderEntity;
import com.alibaba.citrus.cr.unified.inventory.model.AllocateOrderEntityComposeRequest;
import com.alibaba.citrus.cr.unified.inventory.repository.AllocateOrderDomainRepository;
import com.alibaba.citrus.cr.unified.inventory.utils.ToolUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.crunifiedinventory.allocateorderdomain.dto.UpdateStatusRequest;
import com.epoch.app.crunifiedinventory.allocateorderdomain.service.AllocateOrderDomainService;
import com.epoch.app.crunifiedinventory.allocateorderstandardmessage.service.AllocateOrderStandardMessageService;
import com.epoch.app.crunifiedinventory.domain.allocateorder.dto.AllocateOrderLoadListRequest;
import com.epoch.app.crunifiedinventory.domain.allocateorder.model.AllocateOrder;
import com.epoch.app.crunifiedinventory.domain.allocateorder.service.AllocateOrderService;
import com.epoch.app.crunifiedinventory.domain.allocateorderdetail.service.AllocateOrderDetailService;
import com.epoch.app.crunifiedinventory.model.dto.AllocateOrderStandardMessageDTO;
import com.epoch.app.crunifiedinventory.model.enums.AllocateOrderType;
import com.epoch.app.crunifiedinventory.sdo.enums.AllocateOrderTypeEnum;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @description:
 * @author: yuhw
 * @date: 2024年01月22日 17:50
 **/
@Service
@Primary
public class AllocateOrderDomainServiceImpl implements AllocateOrderDomainService {

    private static Log log = Log.getLogger(AllocateOrderDomainServiceImpl.class);
    @Resource
    private AllocateOrderEntityFactory allocateOrderEntityFactory;
    @Resource
    private AllocateOrderStatusHandlerManager allocateOrderStatusHandlerManager;
    @Resource
    private AllocateOrderDomainRepository allocateOrderDomainRepository;
    @Resource
    private PlanAllocateOrderStatusHandler planAllocateOrderStatusHandler;
    @Resource
    private AllocateOrderStandardMessageService allocateOrderStandardMessageService;
    @Resource
    private AllocateOrderService allocateOrderService;

    @FacadeInvoker(value = "更新调拨单主子单状态")
    @Override
    public Result<Void> updateStatus(UpdateStatusRequest updateStatusRequest) {
        log.info("AllocateOrderDomainServiceImpl_updateStatus_request:{}", JSON.toJSONString(updateStatusRequest));
        //更新状态, 根据调拨单类型来更新 计划调拨 / 货场仓调拨 / 仓间调拨
        //1. 构建调拨单主子单信息;
        AllocateOrderEntityComposeRequest composeRequest = AllocateOrderEntityComposeRequest.builder().code(updateStatusRequest.getCode()).build();
        AllocateOrderEntity allocateOrderEntity = allocateOrderEntityFactory.composeAllocateOrderEntity(composeRequest);
        log.info("AllocateOrderDomainServiceImpl_composeAllocateOrderEntity_res:{}",JSON.toJSONString(allocateOrderEntity));
        //这里看是否需要报错了.
        if (allocateOrderEntity == null){
            return Result.success(null);
        }
        //更新当前自身调拨单的状态
        AllocateOrderStatusHandler statusHandler = allocateOrderStatusHandlerManager.getStatusHandler(allocateOrderEntity.getAllocateOrder().getType().toString());
        statusHandler.execute(allocateOrderEntity);
        log.info("AllocateOrderDomainServiceImpl_updateStatus_entity:{}",JSON.toJSONString(allocateOrderEntity));
        allocateOrderDomainRepository.updateStatus(allocateOrderEntity);
        //如果是货场提货单,需要再更改下关联的计划调拨单状态 或者 计划调拨单也需要重新推进下, 因为部分出入的场景, 还需要通过货场提货单来推进
        if (AllocateOrderTypeEnum.FREIGHT_YARD_PICKUP.getType().equals(allocateOrderEntity.getAllocateOrder().getType()) ||
                (AllocateOrderTypeEnum.PLAN.getType().equals(allocateOrderEntity.getAllocateOrder().getType()) &&
                        ToolUtil.isTrainOrSea(allocateOrderEntity.getAllocateOrder().getShipMethod()))){
            log.info("updateStatus_is_freight_yard_pickup");
            /**
             * 获取到所有的货场提货单主单
             * 获取到对应调拨单的明细
             * 即计划调拨单的每行都需要获取到所有对应的调拨单行号的明细.
             * 传出来的是一个对象,还是说直接在handler里更新了?
             */
//            AllocateOrderStatusHandler planOrderPickedStatusHandler = allocateOrderStatusHandlerManager.getStatusHandler(AllocateOrderTypeEnum.PLAN.getType().toString());
            //查询货场提货单到对应的调拨单
            String relatedAllocateOrderCode = null;
            if (AllocateOrderTypeEnum.FREIGHT_YARD_PICKUP.getType().equals(allocateOrderEntity.getAllocateOrder().getType())){
                relatedAllocateOrderCode = allocateOrderEntity.getAllocateOrder().getRelatedAllocateOrderCode();
            }else if (AllocateOrderTypeEnum.PLAN.getType().equals(allocateOrderEntity.getAllocateOrder().getType()) &&
                    ToolUtil.isTrainOrSea(allocateOrderEntity.getAllocateOrder().getShipMethod())){
                relatedAllocateOrderCode = allocateOrderEntity.getAllocateOrder().getCode();
            }
            /**
             * 获取到计划调拨2货场仓的
             * 查出对应的所有的货场提货单及明细
             * 计算计划货场的每行明细状态,再推进主单状态
             *
             */
            AllocateOrderEntityComposeRequest relatedComposeRequest = AllocateOrderEntityComposeRequest.builder()
                    .code(relatedAllocateOrderCode).build();
            AllocateOrderEntity planOrderEntity = allocateOrderEntityFactory.composeAllocateOrderEntity(relatedComposeRequest);
            log.info("updateStatus_get_plan_order_res:{}",JSON.toJSONString(planOrderEntity));
            //TODO 查不到关联的计划调拨单时是否需要报错?
            if (planOrderEntity == null){
                log.error("freightYardReceive_plan_order_empty:{}",relatedAllocateOrderCode);
                return Result.success(null);
            }
            //增加个判断, 如果没有关联的货场提货单可以跳过.
            boolean freightYardPickedUpPushStatus = planAllocateOrderStatusHandler.freightYardPickedUpPushStatus(planOrderEntity);
            if (!freightYardPickedUpPushStatus){
                log.info("freightYardReceive_plan_order_has_not_relatedOrders");
            }
            log.info("updateStatus_freightYardPickedUpPushStatus_result:{}",JSON.toJSONString(planOrderEntity));
            allocateOrderDomainRepository.updateStatus(planOrderEntity);
            //临时加个消息
            try {
                AllocateOrderLoadListRequest allocateOrderLoadListRequest = new AllocateOrderLoadListRequest();
                if (StringUtils.isNotBlank(relatedAllocateOrderCode)){
                    allocateOrderLoadListRequest.setCode(relatedAllocateOrderCode);
                    Result<List<AllocateOrder>> listResult = allocateOrderService.loadAllocateOrderList(allocateOrderLoadListRequest);
                    if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())){
                        AllocateOrder allocateOrder = listResult.getResult().get(0);
                        AllocateOrderStandardMessageDTO messageDTO = AllocateOrderStandardMessageDTO.builder()
                                .keyword(allocateOrder.getCode())
                                .eventCode(MessageEventCodeEnum.EDIT.getCode())
                                .businessCode(MessageBusinessCodeEnum.ALLOCATE_ORDER.getCode())
                                .businessType(allocateOrder.getBusinessType())
                                .fromSys(allocateOrder.getFromSys())
                                .eventTime(new Date())
                                .build();
                        allocateOrderStandardMessageService.sendAllocateOrderStandardMessage(messageDTO);
                    }
                }
            }catch (Throwable e){
                log.error("freightYardPickedUpPushStatus_send_standard_message_error",e);
            }
        }
        return Result.success(null);
    }
}
